import { reactive, ref, toRefs } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Local, consoleError } from "@fast-china/utils";
import { defineStore } from "pinia";
import type { GetLoginUserInfoOutput } from "@/api/services/auth/models/GetLoginUserInfoOutput";
import type { AxiosResponse } from "axios";
import { authApi } from "@/api/services/auth";
import { loginApi } from "@/api/services/login";
import router from "@/router";
import { closeWebSocket } from "@/signalR";

type IState = {
	/** Token */
	token: string;
	/** Refresh Token */
	refreshToken: string;
};

export const useUserInfo = defineStore(
	"userInfo",
	() => {
		const state = reactive<IState & GetLoginUserInfoOutput>({
			token: "",
			refreshToken: "",
			accountKey: "",
			mobile: "",
			nickName: "",
			avatar: "",
			tenantNo: "",
			tenantName: "",
			userKey: "",
			account: "",
			employeeNo: "",
			employeeName: "",
			departmentId: null,
			departmentName: "",
			isSuperAdmin: false,
			isAdmin: false,
			roleNameList: [],
			buttonCodeList: [],
			menuList: [],
		});

		/** 动态生成路由 */
		const asyncRouterGen = ref(false);

		/** WebSocket 是否连接 */
		const hasWebSocket = ref(false);

		/** 设置用户信息 */
		const setUserInfo = (uInfo: GetLoginUserInfoOutput): void => {
			Object.keys(uInfo).forEach((key) => {
				state[key] = uInfo[key];
			});
		};

		/** 删除 Token */
		const removeToken = (): void => {
			state.token = "";
			state.refreshToken = "";
		};

		/** 设置 Token */
		const setToken = (axiosResponse: AxiosResponse): void => {
			if (!axiosResponse) return;
			// 从请求头部中获取 Token
			const token = (axiosResponse.headers.get as (headerName: string) => string)("access-token");
			// 从请求头部中获取 Refresh Token
			const refreshToken = (axiosResponse.headers.get as (headerName: string) => string)("x-access-token");
			// 判断是否为无效 Token
			if (token === "invalid_token") {
				// 删除 Token
				removeToken();
			} else if (token && refreshToken && refreshToken !== "invalid_token") {
				// 设置 Token
				state.token = token;
				state.refreshToken = refreshToken;
			}
		};

		/**
		 * 获取 Token
		 * @description 从缓存中获取
		 */
		const getToken = (): { token: string; refreshToken: string } => {
			return { token: state.token, refreshToken: state.refreshToken };
		};

		/**
		 * 解析Token
		 * @description 如果Token过期，会解析不出来
		 * @param token 可以传入，也可以直接获取 pinia 中的
		 * @param refreshToken 可以传入，也可以直接获取 pinia 中的
		 */
		const resolveToken = (token: string = null, refreshToken: string = null): { token: string; refreshToken: string; tokenData: any } => {
			token ??= state.token;
			refreshToken ??= state.refreshToken;
			if (token) {
				const jwtToken = decodeURIComponent(encodeURIComponent(window.atob(token.replace(/_/g, "/").replace(/-/g, "+").split(".")[1])));
				const jwtTokenData = JSON.parse(jwtToken);
				// 获取 Token 的过期时间
				const exp = new Date(jwtTokenData.exp * 1000);
				if (new Date() >= exp) {
					return { token: `Bearer ${token}`, refreshToken: `Bearer ${refreshToken}`, tokenData: jwtTokenData };
				}
				return { token: `Bearer ${token}`, refreshToken: null, tokenData: jwtTokenData };
			}
			return { token: null, refreshToken: null, tokenData: null };
		};

		/** 登录 */
		const login = (): void => {
			ElMessage.success("登录成功");
			// 确保 getLoginUser 获取用户信息
			asyncRouterGen.value = false;
			// 进入系统
			router.push("/");
		};

		const logoutClear = (): void => {
			removeToken();
			// 删除 HTTP 缓存数据
			Local.removeByPrefix("HTTP_CACHE_");
			// 排除登录页面报错的问题
			if (router.currentRoute.value.path === "/login") {
				router.push({ path: "/login" });
			} else {
				router.push({ path: "/login", query: { redirect: encodeURIComponent(router.currentRoute.value.fullPath) } });
			}
		};

		/** 退出登录 */
		const logout = async (
			data: {
				/**
				 * 1 强制下线
				 * 2 其他地方登录
				 */
				type: 1 | 2;
				message: string;
			} = null
		): Promise<void> => {
			if (data?.type === 2) {
				ElMessageBox.alert(data?.message, {
					type: "warning",
				});
				try {
					// 关闭 WebSocket 连接
					await closeWebSocket();
				} catch (error) {
					consoleError("Logout", error);
				}
				logoutClear();
			} else {
				try {
					// 关闭 WebSocket 连接
					await closeWebSocket();
				} catch (error) {
					consoleError("Logout", error);
				}
				try {
					await loginApi.logout();
				} catch (error) {
					consoleError("Logout", error);
				} finally {
					logoutClear();
					if (data !== null) {
						ElMessageBox.alert(data?.message, {
							type: "warning",
						});
					}
				}
			}
		};

		/** 刷新用户信息 */
		const refreshUserInfo = async (): Promise<void> => {
			const apiRes = await authApi.getLoginUserInfo();
			setUserInfo(apiRes);
		};

		return {
			...toRefs(state),
			asyncRouterGen,
			hasWebSocket,
			setUserInfo,
			removeToken,
			setToken,
			getToken,
			resolveToken,
			login,
			logout,
			logoutClear,
			refreshUserInfo,
		};
	},
	{
		persist: {
			key: "store-user-info",
			// 这里是配置 pinia 只需要持久化 state 中的 Token 即可，而不是整个 store
			pick: ["token", "refreshToken"],
		},
	}
);
